"""
这个模块是为了代替设计混乱的stats.py模块。

这个模块的设计需求没有发生改变，还是为了让数据处理更加的高效的同时使用sympy，以获得精确的数值计算结果。

在设计架构上做出调整，定义一个新的类：Data。
这是因为sympy的stats模块其实是随机概率并不是统计，很多东西用起来不方便或者看起来不是那个意思。

为了方便，Data类继承python的List（后期会考虑同时继承sympy的Matrix）。
"""
# from typing import List

from sympy import *
from sympy import Rational
from sympy.matrices import *
from sympy.core import Integer, Float, Rational

from typing import Union

RealNumber = (int, float, Integer, Float, Rational)


class Data(list):
    """
    this is a child class of list.
    """

    def __add__(self, other):
        if isinstance(other, RealNumber):
            answer = []
            for item in self:
                answer.append(item + other)
            return Data(answer)

        if (type(self) != type(other)) or (len(self) != len(other)):
            raise ValueError
        answer = []
        for i in range(len(self)):
            answer.append(self[i] + other[i])
        return Data(answer)

    __radd__ = __add__

    def __sub__(self, other):
        if isinstance(other, RealNumber):
            answer = []
            for item in self:
                answer.append(item - other)
            return Data(answer)

        if (type(self) != type(other)) or (len(self) != len(other)):
            raise ValueError
        answer = []
        for i in range(len(self)):
            answer.append(self[i] - other[i])
        return Data(answer)

    __rsub__ = __sub__

    def __mul__(self, other):
        if isinstance(other, RealNumber):
            answer = []
            for item in self:
                answer.append(item * other)
            return Data(answer)

        if (type(self) != type(other)) or (len(self) != len(other)):
            raise ValueError
        answer = []
        for i in range(len(self)):
            answer.append(self[i] * other[i])
        return Data(answer)

    __rmul__ = __mul__

    def __div__(self, other):
        if isinstance(other, RealNumber):
            answer = []
            for item in self:
                answer.append(item / other)
            return Data(answer)

        if (type(self) != type(other)) or (len(self) != len(other)):
            raise ValueError
        answer = []
        for i in range(len(self)):
            answer.append(self[i] / other[i])
        return Data(answer)

    def __rdiv__(self, other):
        if isinstance(other, RealNumber):
            answer = []
            for item in self:
                answer.append(other / item)
            return Data(answer)

        if (type(self) != type(other)) or (len(self) != len(other)):
            raise ValueError
        answer = []
        for i in range(len(self)):
            answer.append(other[i] / self[i])
        return Data(answer)

    def _power_matrix(self, n, central=True):
        """
        return is the matrix.
        """
        if central:
            length = len(self)
            mean = self.mean()
            power_matrix = diag(*self) - diag(*([mean] * length))
        else:
            power_matrix = diag(*self)
        # return the Matrix,
        # the traces is the n th power of self.
        return power_matrix**n

    def __pow__(self, n):
        return Data(ones(1, len(self)) * self._power_matrix(n, central=False))

    # fundamental status functions

    def mean(self):
        return sum(self) / len(self)

    def range(self):
        self_shadow = self.copy()
        self_shadow.sort()
        return self_shadow[-1] - self_shadow[0]

    def variance(self, sample=True):
        if sample:
            return trace(self._power_matrix(2)) / (len(self) - 1)
        else:
            return trace(self._power_matrix(2)) / (len(self))

    def percentile(self, percent):
        """这个只是为了方便校对时与书本同步罢了，至于是否符合一般的工业标准，看看就好了。"""
        check_num = len(self) * percent / S(100)
        if check_num in Integers:
            return (self[check_num - 1] + self[check_num]) / 2
        else:
            return self[floor(check_num)]
